package com.example.springboot.scheduled;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.IntervalTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import java.util.concurrent.Executors;

/**
 * 多线程执行定时任务
 * 所有的定时任务都放在一个线程池中，定时任务启动时使用不同都线程。
 * Created by wuning at 2018/8/20 17:53
 **/
@Configuration
@EnableScheduling
public class ScheduledTasksThreadPoolConfig implements SchedulingConfigurer {

    private Logger logger = LoggerFactory.getLogger(getClass());


    @Value("${spring.scheduling.tasks.pool.size:1}")//默认值设为1
    private int poolSize;

    @Value("${spring.scheduling.tasks.fixed.delay:0}")//默认值设为0
    private long fixedDelayValue;//表示当前方法执行完毕XXX ms后，Spring scheduling会再次调用该方法

    @Value("${spring.scheduling.tasks.fixed.rate:0}")//默认值设为0
    private long fixedRateValue;//表示当前方法开始执行XXX ms后，Spring scheduling会再次调用该方法

    @Value("${spring.scheduling.tasks.initial.delay:0}")
    private long initDelayValue;//表示延迟XXX ms执行第一次任务,默认值设为0
    @Value("${spring.scheduling.tasks.initial.fixed.rate:0}")
    private long initFixedRateValue;//默认值设为0


    @Value("${spring.scheduling.tasks.corn:}")//默认值设为空
    private String taskCorn;//定时任务表达式



    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

        //设定一个长度10的定时任务线程池
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(poolSize));

        if(fixedDelayValue>0){
            taskRegistrar.addFixedDelayTask(new FixedDelayRunnable(),fixedDelayValue);
        }

        if(fixedRateValue>0){
            taskRegistrar.addFixedRateTask(new FixedRateRunnable(),fixedRateValue);
        }

        if (initDelayValue >0 && initFixedRateValue >0){
            taskRegistrar.addFixedRateTask(new IntervalTask(new FixedRateInitDelayRunnable(), initFixedRateValue, initDelayValue));
        }

        if(taskCorn != null && !taskCorn.trim().equals("")){
            taskRegistrar.addCronTask(new CronRunnable(),taskCorn);
        }


    }


    private class FixedDelayRunnable implements Runnable{
        @Override
        public void run() {

            //logger.debug("FixedDelayRunnable: 执行方法");
        }
    }

    private class FixedRateRunnable implements Runnable{
        @Override
        public void run() {

            //logger.info("FixedRateRunnable: 执行方法");
        }
    }

    private class FixedRateInitDelayRunnable implements Runnable{
        @Override
        public void run() {

            //logger.error("FixedRateInitDelayRunnable: 执行方法");
        }
    }

    private class CronRunnable implements Runnable{
        @Override
        public void run() {

            //logger.info("CronRunnable: 执行方法");
        }
    }
}

/**定时任务，默认单线程执行，实现SchedulingConfigurer即可实现多线程执行
 *
 *     （1）cron：cron表达式，指定任务在特定时间执行；是由空格隔开的6个域组成，每一个域对应一个含义（秒 分 时 每月第几天 月 星期）
 *          秒：可出现", - * /"四个字符，有效范围为0-59的整数
 *
 *          分：可出现", - * /"四个字符，有效范围为0-59的整数
 *
 *          时：可出现", - * /"四个字符，有效范围为0-23的整数
 *
 *          每月第几天：可出现", - * / ? L W C"八个字符，有效范围为0-31的整数
 *
 *          月：可出现", - * /"四个字符，有效范围为1-12的整数或JAN-DEc
 *
 *          星期：可出现", - * / ? L C #"四个字符，有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天，2表示星期一， 依次类推
 *
 *     ----特殊字符含义--------------------------------------------------------------------------------------------------------
 *
 *     * : 表示匹配该域的任意值，比如在秒*, 就表示每秒都会触发事件。；
 *
 *     ? : 只能用在每月第几天和星期两个域。表示不指定值，当2个子表达式其中之一被指定了值以后，为了避免冲突，需要将另一个子表达式的值设为“?”；
 *
 *     - : 表示范围，例如在分域使用5-20，表示从5分到20分钟每分钟触发一次
 *
 *     / : 表示起始时间开始触发，然后每隔固定时间触发一次，例如在分域使用5/20,则意味着5分，25分，45分，分别触发一次.
 *
 *     , : 表示列出枚举值。例如：在分域使用5,20，则意味着在5和20分时触发一次。
 *
 *     L : 表示最后，只能出现在星期和每月第几天域，如果在星期域使用1L,意味着在最后的一个星期日触发。
 *
 *     W : 表示有效工作日(周一到周五),只能出现在每月第几日域，系统将在离指定日期的最近的有效工作日触发事件。注意一点，W的最近寻找不会跨过月份
 *
 *     LW : 这两个字符可以连用，表示在某个月最后一个工作日，即最后一个星期五。
 *
 *     # : 用于确定每个月第几个星期几，只能出现在每月第几天域。例如在1#3，表示某月的第三个星期日。
 *
 *     ----例子--------------------------------------------------------------------------------------------------------
 *     "0 0 * * * *"                      表示每小时0分0秒执行一次
 *     "*&#47;10 * * * * *"               表示每10秒执行一次
 *     "0 0 8-10 * * *"                   表示每天8，9，10点执行
 *     "0 0/30 8-10 * * *"                表示每天8点到10点，每半小时执行
 *     "0 0 9-17 * * MON-FRI"             表示每周一至周五，9点到17点的0分0秒执行
 *     "0 0 0 25 12 ?"                    表示每年圣诞节（12月25日）0时0分0秒执行
 *
 *     （2）fixedDelay：表示上一次任务执行完成后多久再次执行，参数类型为long，单位ms；
 *
 *     （3）fixedDelayString：与fixedDelay含义一样，只是参数类型变为String；
 *
 *     （4）fixedRate：表示按一定的频率执行任务，参数类型为long，单位ms；
 *
 *     （5）fixedRateString: 与fixedRate的含义一样，只是将参数类型变为String；
 *
 *     （6）initialDelay：表示延迟多久再第一次执行任务，参数类型为long，单位ms；
 *
 *     （7）initialDelayString：与initialDelay的含义一样，只是将参数类型变为String；
 *
 *
 * */